<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>贪吃蛇</title>
    <style>
      body {
        width: 100vw;
        height: 100vh;
        display: flex;
        justify-content: center;
        align-items: center;
      }
      canvas {
        box-shadow: 0 0 10px #ccc;
      }
    </style>
  </head>
  <body>
    <canvas width="800" height="600" id="canvas"></canvas>
    <script>
      let canvas = document.getElementById('canvas')
      let timer = null
      if (canvas.getContext) {
        let ctx = canvas.getContext('2d')
        /*
          贪吃蛇步骤
            1. 先把蛇画出来
              1.1 蛇头和蛇身
            2. 让蛇动起来
              2.1 添加键盘按下事件
              2.2 animate运动
            3. 随机投放食物
              3.1 坐标位置
              3.2 食物是否投放到蛇的身上（数组去重）
            4. 吃食物
              4.1 碰撞检测
              4.2 将食物添加到蛇身上
            5. 边缘检测，判断游戏是否结束
              5.1 碰撞检测
              5.2 gameover
        */
        function Rect(x, y, width, height, color) {
          this.x = x
          this.y = y
          this.width = width
          this.height = height
          this.color = color
        }
        Rect.prototype.rDraw = function() {
          // console.log('123456')
          ctx.beginPath()
          ctx.fillStyle = this.color
          ctx.fillRect(this.x, this.y, this.width, this.height)
          ctx.strokeRect(this.x, this.y, this.width, this.height)
          ctx.closePath()
        }

        function Snake() {
          // 蛇头
          this.head = new Rect(
            canvas.width / 2,
            canvas.height / 2,
            40,
            40,
            'red'
          )
          this.isEeaFood = false // 是否吃到食物的状态
          this.direction = 2
          // 蛇身
          this.body = new Array()
          let x = this.head.x - 40
          let y = this.head.y
          for (let i = 0; i < 3; i++) {
            let recta = new Rect(x, y, 40, 40, 'gray')
            this.body.push(recta)
            x -= 40
          }
        }

        Snake.prototype.sDraw = function() {
          // 绘制蛇头
          this.head.rDraw()
          // 绘制蛇身
          for (let i = 0; i < this.body.length; i++) {
            this.body[i].rDraw()
          }
        }

        Snake.prototype.move = function() {
          /*
            蛇能够动起来的思路就是给蛇加头去尾 再重新渲染
          */
          // 加头
          let rect = new Rect(
            this.head.x,
            this.head.y,
            this.head.width,
            this.head.height,
            'gray'
          )
          this.body.splice(0, 0, rect)

          // 去尾
          if (this.isEeaFood == false) {
            this.body.pop() //
          } else {
            this.isEeaFood = false
          }
          console.log(this.body)
          switch (this.direction) {
            case 0: {
              this.head.x -= this.head.width
              break
            }
            case 1: {
              this.head.y -= this.head.height
              break
            }
            case 2: {
              this.head.x += this.head.width
              break
            }
            case 3: {
              this.head.y += this.head.height
              break
            }
          }

          // 判断蛇和边框相撞
          if (
            this.head.x > canvas.width - 40 ||
            this.head.x <= 0 ||
            this.head.y > canvas.height ||
            this.head.y < 0
          ) {
            clearInterval(timer)
            alert('Game Over~')
          }

          // 判断蛇身和蛇头重叠
          for (let i = 0; i < this.body.length; i++) {
            // console.log(this.body[i])
            if (isRectHit(this.head, this.body[i])) {
              clearInterval(timer)
              alert('Game Over~')
            }
          }
        }

        let snake = new Snake()
        snake.sDraw()
        let food = new randForFood()

        function animate() {
          ctx.clearRect(0, 0, canvas.width, canvas.height)
          food.rDraw()
          snake.move()
          snake.sDraw()

          if (isRectHit(snake.head, food)) {
            snake.isEeaFood = true
            food = new randForFood()
          }
        }

        timer = setInterval(() => {
          animate()
        }, 200)

        document.addEventListener('keydown', e => {
          switch (e.keyCode) {
            case 37: {
              snake.direction = 0
              break
            }
            case 38: {
              snake.direction = 1
              break
            }
            case 39: {
              snake.direction = 2
              break
            }
            case 40: {
              snake.direction = 3
              break
            }
          }
        })

        function randForFood() {
          let isInSnake = true
          let rect
          while (isInSnake) {
            // 随机投放的位置
            let x = getRandInRange(0, (canvas.width - 40) / 40) * 40
            let y = getRandInRange(0, (canvas.height - 40) / 40) * 40

            // 食物矩形
            rect = new Rect(x, y, 40, 40, 'green')

            // 判断食物是否与蛇头重叠
            if (isRectHit(snake.head, rect)) {
              isInSnake = true
              continue
            }
            isInSnake = false
            // 判断是否是否与蛇身重叠
            for (let i = 0; i < snake.body.length; i++) {
              if (isRectHit(rect, snake.body[i])) {
                isInSnake = true
                break
              }
            }
          }
          return rect
        }

        // 碰撞检测
        function isRectHit(rect1, rect2) {
          let minx1 = rect1.x
          let minx2 = rect2.x
          let miny1 = rect1.y
          let miny2 = rect2.y

          let maxx1 = rect1.x + rect1.width
          let maxx2 = rect2.x + rect2.width
          let maxy1 = rect1.y + rect1.height
          let maxy2 = rect2.y + rect2.height

          let minX = Math.max(minx1, minx2)
          let minY = Math.max(miny1, miny2)
          let maxX = Math.min(maxx1, maxx2)
          let maxY = Math.min(maxy1, maxy2)

          if (minX < maxX && minY < maxY) {
            return true
          } else {
            return false
          }
        }

        // 获取随机数方法
        function getRandInRange(min, max) {
          return Math.round(Math.random() * (max - min) + min)
        }

        // console.log(111)
        // let recta = new rect(canvas.width / 2, canvas.height / 2, 40, 40, 'red')
        // recta.draw()
      }
    </script>
  </body>
</html>
